﻿//-----------------------------------------------------------------------------------------------------------
// WBFSSync Project by Omega Frost 
// http://wbfssync.codeplex.com/
//
// WBFSSync is Licensed under the terms of the 
// Microsoft Reciprocal License (Ms-RL)
//-----------------------------------------------------------------------------------------------------------
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using WBFSe3;
using WBFSe3.Formats;
using WBFSe3.IO;
using WBFSe3.Wbfs;
using WbfsSync.Controls;
using WbfsSync.Core;
using WbfsSync.Core.Operations;
using WbfsSync.Themes;
using System.Media;
using System.Windows.Media;
using WbfsSync.Dialogs;

namespace WbfsSync
{
    //-------------------------------------------------------------------------------------------------------
    // Interaction logic for MainWindow.xaml
    //-------------------------------------------------------------------------------------------------------
    public partial class MainWindow : Window
    {
        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        public static readonly DependencyProperty IsFatWbfsSelectedProperty = DependencyProperty.Register(
            "IsFatWbfsSelected", typeof(bool?), typeof(MainWindow));


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        ObservableCollection<BrowserItemData> browserCollection =
            new ObservableCollection<BrowserItemData>();

        ViewSelector selector = null;

        WbfsFileInfo[] clipboard = null;
        bool cutClipboard = false;

        //MediaPlayer navigationClick = null;


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        public ObservableCollection<BrowserItemData> BrowserCollection
        { get { return this.browserCollection; } }

        public bool? IsFatWbfsSelected
        {
            get { return base.GetValue(IsFatWbfsSelectedProperty) as bool?; }
            set { base.SetValue(IsFatWbfsSelectedProperty, value); }
        }

        public static RoutedUICommand FormatCommand = new RoutedUICommand("Format", "Format",
            typeof(MainWindow), new InputGestureCollection(new InputGesture[] { }));

        public static RoutedUICommand SetWbfsCommand = new RoutedUICommand("SetWbfs", "SetWbfs",
            typeof(MainWindow), new InputGestureCollection(new InputGesture[] { }));

        public static RoutedUICommand NewLibraryCommand = new RoutedUICommand("NewLibrary", "NewLibrary",
            typeof(MainWindow), new InputGestureCollection(new InputGesture[] { }));

        public static RoutedUICommand RemoveLibraryCommand = new RoutedUICommand("RemoveLibrary", "RemoveLibrary",
            typeof(MainWindow), new InputGestureCollection(new InputGesture[] { }));


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        public MainWindow()
        {
            InitializeComponent();
            Focus();

            // Click Sound
            //this.navigationClick = new MediaPlayer();
            //this.navigationClick.Open(new Uri("pack://application:,,/Sounds/click.wav"));

            // Commands
            CommandBindings.Add(new CommandBinding(FormatCommand, Format, CanFormat));
            CommandBindings.Add(new CommandBinding(SetWbfsCommand, SetWbfs, CanSetWbfs));
            CommandBindings.Add(new CommandBinding(NewLibraryCommand, NewLibrary, CanNewLibrary));
            CommandBindings.Add(new CommandBinding(RemoveLibraryCommand, RemoveLibrary, CanRemoveLibrary));

            // Patch: Solve XAML Binding problem...
            menuFormat.Command = FormatCommand;
            menuFatWbfs.Command = SetWbfsCommand;
            menuNewLibrary.Command = NewLibraryCommand;
            menuRemoveLibrary.Command = RemoveLibraryCommand;

            // Engine
            WbfsLoader.LoadBuiltIn();

            // Patch: Solve XAML Binding problem...
            foreach (WbfsFormat f in WbfsLoader.GetLoadedFormats())
            {
                if (f.Extension != String.Empty)
                {
                    this.pasteAsMenu.Items.Add(new MenuItem
                    {
                        Header = f.Name,
                        Command = ApplicationCommands.Paste,
                    });
                }
            }
            
            // Devices
            HotSwap.DeviceInserted += new DeviceEventHandler(AddDevice);
            HotSwap.DeviceRemoved += new DeviceEventHandler(RemoveDevice);

            // Navigation
            this.navigationForward.Click += new RoutedEventHandler(NavigateForward);
            this.navigationBackward.Click += new RoutedEventHandler(NavigateBackward);
            this.addressBar.PathChanged += new PathChangedEventHandler(LoadPath);
            this.searchBar.SearchQueryChanged += new EventHandler(SetSearchQuery);
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        protected override void OnSourceInitialized(EventArgs e)
        {
            Char drive = '?';

            base.OnSourceInitialized(e);

            // Load Config
            Core.Config.Load();

            // WndProc
            HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
            source.AddHook(WndProc);

            // UI
            NativeLayout.RemoveIcon(this);
            NativeLayout.ExtendGlass(this, menuGrid.Margin);

            try
            {
                // Drive Mapping
                for (drive = 'A'; drive <= 'Z'; drive++)
                {
                    WbfsDriveInfo d;
                    if (WbfsDriveInfo.GetDrive(drive + ":\\", out d) == WbfsError.Ok)
                        AddDevice(d, WbfsError.Ok);
                }
            }
            catch (Exception exception)
            {
                DialogException d = new DialogException(exception, "Drive " + drive);
                d.ShowDialog();
                Close();
            }

            try
            {
                // Libraries
                foreach (String lib in Config.Libraries)
                    AddLibraryLink(lib);
            }
            catch (Exception exception)
            {
                DialogException d = new DialogException(exception, "");
                d.ShowDialog();
                Close();
            }

            // Browser Mode
            SetBrowserMode(Config.BrowserMode);

            // Load Computer
            this.addressBar.SetPath(@"%computer%");
            LoadPath(this.addressBar.Path);
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            // Save Config
            Core.Config.Save();

            base.OnClosing(e);
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            //----------------------------------------------
            if (Native.IsDeviceEvent(msg, wParam.ToInt64()))
                HotSwap.HandleDeviceEvent(hwnd, msg, wParam, lParam, ref handled);

            //----------------------------------------------
            return IntPtr.Zero;
        }


        // Path / Folder

        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void LoadPath(String path)
        {
            // CLICK!!
            //this.navigationClick.Play();

            // Cancel loading
            FileOp.StopLoadingFolder();

            // Clear the collection
            this.browserCollection.Clear();

            // Resolve environment variables
            path = EnvVars.Expand(path);
            if (EnvVars.HasVar(path))
            {
                // Load a special folder

                if (path.StartsWith("%computer%", StringComparison.CurrentCultureIgnoreCase))
                {
                    FileOp.LoadComputer(new OperationDelegate(FileLoadedAsync));
                }
                else if (path.StartsWith("%libraries%", StringComparison.CurrentCultureIgnoreCase))
                {
                    FileOp.BeginLoadingLibraries(new OperationDelegate(FileLoadedAsync));
                }
            }
            else
            {
                if (!Path.IsPathRooted(path))
                    path = Path.GetFullPath(path);

                // Load a path
                FileOp.BeginLoadingFolder(path, new
                    OperationDelegate(FileLoadedAsync));
            }
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private String GetPasteFolder(object source)
        {
            String path = null;
            if ((source is ListViewItem) &&
                (this.fileBrowser.SelectedItems.Count == 1) &&
                (source as ListViewItem).IsSelected)
            {
                BrowserItemData data = this.fileBrowser.SelectedItem as BrowserItemData;
                if (data.IsFolder || data.IsDrive)
                    path = (data.obj as FileSystemInfo).FullName;
            }

            if (path == null) path = EnvVars.
                 Expand(this.addressBar.Path);

            return path;
        }


        // Device Add / Remove

        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void AddDevice(WbfsDriveInfo drive, WbfsError error)
        {
            if (drive.IsReady)
            {
                QuickLink link = new QuickLink();
                link.Text = Core.Language.GetDriveString(drive);
                link.Link = "%computer%\\" + drive.Name;
                link.Icon = Extensions.GetFolderMiniature(link.Link);
                link.Level = 10;
                link.Name = drive.Name[0].ToString();
                
                this.quickComputer.Items.Add(link);

                if (this.addressBar.Path.ToLower() == "%computer%\\")
                    LoadPath(addressBar.Path);
            }
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void RemoveDevice(WbfsDriveInfo drive, WbfsError error)
        {
            for (int i = 0; i < this.quickComputer.Items.Count; i++)
            {
                if ((this.quickComputer.Items[i] as QuickLink).Name == drive.Name[0].ToString())
                    this.quickComputer.Items.RemoveAt(i);
            }

            if (this.addressBar.Path.ToLower() == "%computer%\\")
            {
                LoadPath(addressBar.Path);
            }
            else if (this.addressBar.Path.ToLower().StartsWith("%computer%\\" + drive.Name))
            {
                this.addressBar.SetPath("%computer%");
                FileOp.LoadComputer(new OperationDelegate(FileLoadedAsync));
            }
        }


        // Navigation Bar

        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void NavigateBackward(object sender, RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void NavigateForward(object sender, RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void SetSearchQuery(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
        }


        // Menu

        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void ConfigClick(object sender, RoutedEventArgs e)
        {
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void HelpClick(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Process.Start("http://wbfssync.codeplex.com/documentation");
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void DonateClick(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Process.Start("http://wbfssync.codeplex.com/");
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void CycleModeClick(object sender, RoutedEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            Point p = Mouse.GetPosition(element);
            if (p.X >= element.ActualWidth - 19)
            {
                this.selector = new ViewSelector();
                this.selector.SelectedModeChanged += new EventHandler(ViewSelectorChanged);
                this.selector.WindowStartupLocation = WindowStartupLocation.Manual;

                p = this.PointToScreen(Mouse.GetPosition(this));
                this.selector.Top = Math.Max(0, p.Y - this.selector.Height / 2.0);
                this.selector.Left = Math.Min(System.Windows.SystemParameters.FullPrimaryScreenWidth -
                    this.selector.Width, p.X);

                this.selector.Show();
            }
            else
            {
                SetBrowserMode((BrowserMode)(((int)Config.BrowserMode + 1) % 6));
                LoadPath(addressBar.Path);
            }
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void ViewSelectorChanged(object sender, EventArgs e)
        {
            SetBrowserMode(this.selector.SelectedMode);
            this.selector = null;

            LoadPath(addressBar.Path);
        }


        // Browser
        
        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void FileBrowserClick(object sender, MouseButtonEventArgs e)
        {
            if (e.OriginalSource is ScrollViewer)
                this.fileBrowser.SelectedItem = null;
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void FileBrowserDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (this.fileBrowser.SelectedItems.Count != 1)
                return;

            Open(null, null);
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void LinkClicked(object sender, MouseButtonEventArgs e)
        {
            QuickLink link = this.quickLinksPanel.SelectedItem as QuickLink;
            if (link == null) return;

            this.addressBar.SetPath(link.Link);
            LoadPath(link.Link);
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void FileLoadedAsync(Operation sender, WbfsError error, int element)
        {
            FolderOperation op = sender as FolderOperation;

            if (element >= 0)
            {
                this.fileBrowser.Dispatcher.BeginInvoke(new ParameterizedThreadStart(FileLoaded),
                    (Object)(op.CurrentFile));
                this.addressBar.BeginSetProgress(op.TotalCount, op.Total);
            }
            else
            {
                this.addressBar.BeginSetProgress(0, 0);
            }
        }
        
        
        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void FileLoaded(Object o)
        {
            if (o != null)
            {
                BrowserItemData d;
                if (o is WbfsFileInfo) d = new BrowserItemData(o as WbfsFileInfo, this.fileBrowser.Dispatcher);
                else if (o is DirectoryInfo) d = new BrowserItemData(o as DirectoryInfo, this.fileBrowser.Dispatcher);
                else if (o is WbfsDriveInfo) d = new BrowserItemData(o as WbfsDriveInfo, this.fileBrowser.Dispatcher);
                else if (o is FileInfo)
                {
                    String path, icon;

                    if (Extensions.IsLnk(o as FileInfo))
                    {
                        Extensions.GetShortcutPath(o as FileInfo,
                            out path, out icon);

                        d = new BrowserItemData(o as FileInfo,
                            path, icon, this.fileBrowser.Dispatcher);
                    }
                    else if (Extensions.IsURL(o as FileInfo))
                    {
                        Extensions.GetURLPath(o as FileInfo,
                            out path, out icon);

                        d = new BrowserItemData(o as FileInfo,
                            path, icon, this.fileBrowser.Dispatcher);
                    }
                    else
                    {
                        d = new BrowserItemData(o as FileInfo,
                            this.fileBrowser.Dispatcher);
                    }
                }
                else d = null;

                this.browserCollection.Add(d);
            }
        }
        
        
        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void OperationFinishedAsync(Operation sender, WbfsError error, int element)
        {
            this.Dispatcher.BeginInvoke(new ThreadStart(OperationFinished));
        }
        
        
        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void OperationFinished()
        {
            LoadPath(this.addressBar.Path);
        }
        
        
        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void SetBrowserMode(BrowserMode mode)
        {
            Config.BrowserMode = mode;
            String resource = "Icons/Menu/";

            switch (mode)
            {
                case BrowserMode.Detail:
                    resource += "icon_iconsize_detail.png";
                    this.fileBrowser.View = this.fileBrowser.FindResource("detailModeView") as ViewBase;
                    this.fileBrowser.ItemContainerStyle = this.fileBrowser.FindResource("detailListViewItemStyle") as Style;
                    break;

                case BrowserMode.Tile:
                    resource += "icon_iconsize_tile.png";
                    this.fileBrowser.View = this.fileBrowser.FindResource("tileModeView") as ViewBase;
                    (this.fileBrowser.View as PlainView).ItemWidth = Config.ItemWidths[(int)Config.BrowserMode];
                    this.fileBrowser.ItemContainerStyle = this.fileBrowser.FindResource("tileListViewItemStyle") as Style;
                    break;

                case BrowserMode.Small:
                    resource += "icon_iconsize_small.png";
                    this.fileBrowser.View = this.fileBrowser.FindResource("smallModeView") as ViewBase;
                    (this.fileBrowser.View as PlainView).ItemWidth = Config.ItemWidths[(int)Config.BrowserMode];
                    this.fileBrowser.ItemContainerStyle = this.fileBrowser.FindResource("tileListViewItemStyle") as Style;
                    break;

                case BrowserMode.Medium:
                    resource += "icon_iconsize_medium.png";
                    this.fileBrowser.View = this.fileBrowser.FindResource("largeModeView") as ViewBase;
                    (this.fileBrowser.View as PlainView).ItemWidth = Config.ItemWidths[(int)Config.BrowserMode];
                    this.fileBrowser.ItemContainerStyle = this.fileBrowser.FindResource("tileListViewItemStyle") as Style;
                    break;

                case BrowserMode.Large:
                    resource += "icon_iconsize_large.png";
                    this.fileBrowser.View = this.fileBrowser.FindResource("largeModeView") as ViewBase;
                    (this.fileBrowser.View as PlainView).ItemWidth = Config.ItemWidths[(int)Config.BrowserMode];
                    this.fileBrowser.ItemContainerStyle = this.fileBrowser.FindResource("tileListViewItemStyle") as Style;
                    break;

                case BrowserMode.Extra:
                    resource += "icon_iconsize_extralarge.png";
                    this.fileBrowser.View = this.fileBrowser.FindResource("largeModeView") as ViewBase;
                    (this.fileBrowser.View as PlainView).ItemWidth = Config.ItemWidths[(int)Config.BrowserMode];
                    this.fileBrowser.ItemContainerStyle = this.fileBrowser.FindResource("tileListViewItemStyle") as Style;
                    break;
            }

            this.imageBrowserMode.Source = Extensions.LoadImageLocal(resource);
        }
        

        // Links

        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void AddLibraryLink(String path)
        {
            DirectoryInfo d = new DirectoryInfo(path);

            QuickLink q = new QuickLink();
            q.Icon = Extensions.GetFolderIcon(d, 16);
            q.Link = d.FullName;
            q.Text = d.Name;
            q.Level = 10;
            this.quickLibraries.Items.Add(q);
        }


        // Operations

        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void CanCut(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.fileBrowser == null)
                return;

            if (this.fileBrowser.SelectedItems.Count == 0)
                e.CanExecute = false;
            else
            {
                e.CanExecute = true;
                foreach (BrowserItemData d in this.fileBrowser.SelectedItems)
                    if (!d.IsGame) e.CanExecute = false;
            }
        }

        private void CanCopy(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.fileBrowser == null)
                return;

            if (this.fileBrowser.SelectedItems.Count == 0)
                e.CanExecute = false;
            else
            {
                e.CanExecute = true;
                foreach (BrowserItemData d in this.fileBrowser.SelectedItems)
                    if (!d.IsGame) e.CanExecute = false;
            }
        }

        private void CanPaste(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.fileBrowser == null)
                return;

            e.CanExecute = (this.clipboard != null) && (this.clipboard.Length > 0) &&
                !EnvVars.VirtualPlace(GetPasteFolder(e.OriginalSource));
        }

        private void CanOpen(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.fileBrowser == null)
                return;

            e.CanExecute = (this.fileBrowser.SelectedItem != null) &&
                ((this.fileBrowser.SelectedItem as BrowserItemData).IsFolder ||
                (this.fileBrowser.SelectedItem as BrowserItemData).IsShortcut ||
                (this.fileBrowser.SelectedItem as BrowserItemData).IsDrive);
        }

        private void CanBack(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void CanDelete(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.fileBrowser == null)
                return;

            if (this.fileBrowser.SelectedItems.Count == 0)
                e.CanExecute = false;
            else
            {
                e.CanExecute = true;
                foreach (BrowserItemData d in this.fileBrowser.SelectedItems)
                    if (!d.IsGame) e.CanExecute = false;
            }
        }

        private void CanRename(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.fileBrowser == null)
                return;

            e.CanExecute = (this.fileBrowser.SelectedItems.Count == 1)
                && (this.fileBrowser.SelectedItem as BrowserItemData).IsGame;
        }

        private void CanFormat(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.fileBrowser == null)
                return;

            e.CanExecute = (this.fileBrowser.SelectedItems.Count == 1)
                && (this.fileBrowser.SelectedItem as BrowserItemData).IsDrive
                && (Char.ToUpper(Environment.SystemDirectory[0]) != 
                ((this.fileBrowser.SelectedItem as BrowserItemData).obj as WbfsDriveInfo).Name[0]);
        }

        private void CanSetWbfs(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.fileBrowser == null)
                return;

            e.CanExecute = (this.fileBrowser.SelectedItems.Count == 1)
                && (this.fileBrowser.SelectedItem as BrowserItemData).IsDrive
                && (Char.ToUpper(Environment.SystemDirectory[0]) != 
                ((this.fileBrowser.SelectedItem as BrowserItemData).obj as WbfsDriveInfo).Name[0])
                && !((this.fileBrowser.SelectedItem as BrowserItemData).obj as WbfsDriveInfo).IsWbfs;

            this.menuFatWbfs.IsChecked = e.CanExecute &&
                ((this.fileBrowser.SelectedItem as BrowserItemData).obj as WbfsDriveInfo).IsFatWbfs;
        }

        private void CanNewLibrary(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.addressBar == null)
                return;

            e.CanExecute = this.addressBar.Path == "%libraries%\\";
        }

        private void CanRemoveLibrary(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.addressBar == null)
                return;

            if (this.addressBar.Path != "%libraries%\\")
                return;

            if (this.fileBrowser.SelectedItems.Count == 0)
                e.CanExecute = false;
            else
            {
                e.CanExecute = true;
                foreach (BrowserItemData d in this.fileBrowser.SelectedItems)
                    if (!d.IsFolder) e.CanExecute = false;
            }
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private void Cut(object sender, ExecutedRoutedEventArgs e)
        {
            this.cutClipboard = true;
            this.clipboard = (from BrowserItemData d in this.fileBrowser.SelectedItems
                              select d.obj as WbfsFileInfo).ToArray();
        }

        private void Copy(object sender, ExecutedRoutedEventArgs e)
        {
            this.cutClipboard = false;
            this.clipboard = (from BrowserItemData d in this.fileBrowser.SelectedItems
                              select d.obj as WbfsFileInfo).ToArray();
        }

        private void Paste(object sender, ExecutedRoutedEventArgs e)
        {
            String path = GetPasteFolder(e.OriginalSource);
            FileOp.BeginCopy(this.clipboard, path, null, this.cutClipboard,
                new OperationDelegate(OperationFinishedAsync));
        }

        private void Open(object sender, ExecutedRoutedEventArgs e)
        {
            BrowserItemData data = this.fileBrowser.SelectedItem as BrowserItemData;
            if (data.IsFolder)
            {
                DirectoryInfo di = data.obj as DirectoryInfo;

                this.addressBar.AppendPath(di.Name);
                LoadPath(this.addressBar.Path);
            }
            else if (data.IsDrive)
            {
                WbfsDriveInfo di = data.obj as WbfsDriveInfo;

                this.addressBar.AppendPath(di.Name);
                LoadPath(this.addressBar.Path);
            }
            else if (data.IsShortcut && data.IsShortcutDir)
            {
                String path = "%computer%" + (string)data.meta;
                this.addressBar.SetPath(path);
                LoadPath(path);
            }
        }

        private void Back(object sender, ExecutedRoutedEventArgs e)
        {
        }

        private void Delete(object sender, ExecutedRoutedEventArgs e)
        {
            if (MessageBox.Show("Permanently delete files?", "WbfsSync",
                MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                var files = from BrowserItemData d
                            in this.fileBrowser.SelectedItems
                            select d.obj as WbfsFileInfo;

                FileOp.BeginDelete(files.ToArray(), new
                    OperationDelegate(OperationFinishedAsync));
            }
        }

        private void Rename(object sender, ExecutedRoutedEventArgs e)
        {
        }

        private void Format(object sender, ExecutedRoutedEventArgs e)
        {
            WbfsError error;
            WbfsDevice device;
            BrowserItemData data = this.fileBrowser.
                SelectedItem as BrowserItemData;

            if (MessageBox.Show("Formatting will erase ALL data on the disk, continue?",
                    "WbfsSync", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
            {
                error = WbfsDevice.Format((data.obj as WbfsDriveInfo).Name, out device);
                if (error != WbfsError.Ok)
                {
                    MessageBox.Show(String.Format("Error formatting disk, error {0}", error),
                        "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }

            OperationFinished();
        }

        private void SetWbfs(object sender, ExecutedRoutedEventArgs e)
        {
            WbfsDriveInfo drive = (this.fileBrowser.SelectedItem 
                as BrowserItemData).obj as WbfsDriveInfo;
            drive.IsFatWbfs = !drive.IsFatWbfs;

            (this.fileBrowser.SelectedItem as BrowserItemData).Update("Name");
        }

        private void NewLibrary(object sender, ExecutedRoutedEventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog dlg = 
                new System.Windows.Forms.FolderBrowserDialog();

            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                String path = dlg.SelectedPath;

                if (!path.EndsWith("\\"))
                    path += "\\";

                if (!Config.Libraries.Contains(path, StringComparer.CurrentCultureIgnoreCase))
                {
                    Config.Libraries.Add(path);
                    AddLibraryLink(path);
                }
            }

            LoadPath(this.addressBar.Path);
        }

        private void RemoveLibrary(object sender, ExecutedRoutedEventArgs e)
        {
            BrowserItemData d = this.fileBrowser.SelectedItem as BrowserItemData;
            DirectoryInfo di = d.obj as DirectoryInfo;

            for (int i = 0; i < Config.Libraries.Count; i++)
            {
                if (String.Compare(Config.Libraries[i], di.FullName,
                    StringComparison.CurrentCultureIgnoreCase) == 0)
                {
                    Config.Libraries.RemoveAt(i);
                }
            }

            LoadPath(this.addressBar.Path);
        }
    }
}
